#include <GL/glew.h>
#include <GL/freeglut.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <cstdio>
#include <common/common.hpp>

GLfloat vertices[] = {
	// order of coordinates: X, Y, Z, W, R, G, B
    // triangle Fan
     0.0f,  0.0f, 0.0f,  1.5f,	1.0f, 1.0f, 1.0f,         
    -0.5f, -0.8f, 0.0f,  1.0f,	0.7f, 0.7f, 0.7f,            
     0.5f, -0.8f, 0.0f,  1.0f,	0.7f, 0.7f, 0.7f,
     0.5f,  0.8f, 0.0f,  2.0f,	0.7f, 0.7f, 0.7f,
    -0.5f,  0.8f, 0.0f,  2.0f,	0.7f, 0.7f, 0.7f,
    -0.5f, -0.8f, 0.0f,  1.0f,	0.7f, 0.7f, 0.7f,

    // line 1
    -0.5f,  0.0f, 0.0f,  1.5f,	1.0f, 0.0f, 0.0f,
     0.5f,  0.0f, 0.0f,  1.5f,	1.0f, 0.0f, 0.0f,

    // mallets
     0.0f, -0.4f, 0.0f, 1.25f,	0.0f, 0.0f, 1.0f,
     0.0f,  0.4f, 0.0f, 1.75f,	1.0f, 0.0f, 0.0f,
};

static GLuint _program;
static GLuint _matloc;

static GLboolean
init() {
	GLenum err = glewInit();
	if (err != GLEW_OK) {
		logv("fail to init glew");
		return GL_FALSE;
	}

	if (!GLEW_VERSION_3_3) {
		logv("not support for ogl3.3");
		return GL_FALSE;
	}
	logv("support for ogl3.3");

	glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
	glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); // to enable set gl_PointSize in vertex shader

    _program = shader_util::linkprogram("./res/simple_vertex_shader.glsl", "./res/simple_fragment_shader.glsl");
    if (_program == 0)
    	return GL_FALSE;

    _matloc = glGetUniformLocation(_program, "u_matrix");

    logv("init finish successfully");
    return GL_TRUE;
}

static void
cb_display() {
	logv("cb_display");
   	glClear(GL_COLOR_BUFFER_BIT);

   	glUseProgram(_program);
   		GLsizei stride = sizeof(GLfloat) * 7;
	    glEnableVertexAttribArray(0);
	    glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, stride, vertices);
	    glEnableVertexAttribArray(1);
	    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, stride, vertices + 4);
	    
	    glDrawArrays(GL_TRIANGLE_FAN, 0, 6);
	    
	    glDrawArrays(GL_LINES, 6, 2); 
	    
	    glDrawArrays(GL_POINTS, 8, 1);

	    glDrawArrays(GL_POINTS, 9, 1);
	glUseProgram(0);

	glFlush();
}

static void 
cb_reshape(int width, int height) {
	logv("cb_reshape: width:%d, height:%d", width, height);
	glViewport (0, 0, width, height);

	glm::mat4x4 matrix;
	GLfloat aspect = (GLfloat)width / (GLfloat)height;
	if (width > height)
		matrix = glm::ortho(-aspect, aspect, -1.0f, 1.0f, -1.0f, 1.0f);
	else
		matrix = glm::ortho(-1.0f, 1.0f, -aspect, aspect, -1.0f, 1.0f);

	glUseProgram(_program);
	glUniformMatrix4fv(_matloc, 1, GL_FALSE, glm::value_ptr(matrix));
}

static void
cb_close() {
	logv("cb_close");
	glDeleteProgram(_program);
}

int
main(int argc, char *argv[]) {
	glutInit(&argc, argv);
	glutInitWindowSize(800, 600);
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
	glutInitWindowPosition(0, 0);
	
	glutCreateWindow("AirHockey - 3D with perspective division (<x,y,z,w>/w)");
	
	if (init() == GL_FALSE)
		return 0;

	glutDisplayFunc(cb_display);
	glutReshapeFunc(cb_reshape);
	glutCloseFunc(cb_close);

	glutMainLoop();
	return 0;
}
